﻿// Decompiled with JetBrains decompiler
// Type: Commom.Util.Lambda
// Assembly: MT5Trade, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 8045A2CB-DBD6-41AD-8804-F98CAC1BDC8D
// Assembly location: C:\projects\trade\trade_tool\trade0812\MT5Trade.dll

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

#nullable enable
namespace Commom.Util;

public static class Lambda
{
  public static Type GetType(Expression expression) => Lambda.GetMemberExpression(expression)?.Type;

  public static MemberInfo GetMember(Expression expression)
  {
    return Lambda.GetMemberExpression(expression)?.Member;
  }

  public static MemberExpression GetMemberExpression(Expression expression, bool right = false)
  {
    if (expression == null)
      return (MemberExpression) null;
    switch (expression.NodeType)
    {
      case ExpressionType.Call:
        return Lambda.GetMethodCallExpressionName(expression);
      case ExpressionType.Convert:
      case ExpressionType.Not:
        return Lambda.GetMemberExpression(((UnaryExpression) expression).Operand, right);
      case ExpressionType.Equal:
      case ExpressionType.GreaterThan:
      case ExpressionType.GreaterThanOrEqual:
      case ExpressionType.LessThan:
      case ExpressionType.LessThanOrEqual:
      case ExpressionType.NotEqual:
        return Lambda.GetMemberExpression(right ? ((BinaryExpression) expression).Right : ((BinaryExpression) expression).Left, right);
      case ExpressionType.Lambda:
        return Lambda.GetMemberExpression(((LambdaExpression) expression).Body, right);
      case ExpressionType.MemberAccess:
        return (MemberExpression) expression;
      default:
        return (MemberExpression) null;
    }
  }

  private static MemberExpression GetMethodCallExpressionName(Expression expression)
  {
    MethodCallExpression methodCallExpression = (MethodCallExpression) expression;
    MemberExpression callExpressionName1 = (MemberExpression) methodCallExpression.Object;
    if (Commom.Util.Reflection.IsGenericCollection(callExpressionName1?.Type))
    {
      Expression callExpressionName2 = methodCallExpression.Arguments.FirstOrDefault<Expression>();
      if (callExpressionName2 != null && callExpressionName2.NodeType == ExpressionType.MemberAccess)
        return (MemberExpression) callExpressionName2;
    }
    return callExpressionName1;
  }

  public static string GetName(Expression expression)
  {
    return Lambda.GetMemberName(Lambda.GetMemberExpression(expression));
  }

  public static string GetMemberName(MemberExpression memberExpression)
  {
    if (memberExpression == null)
      return string.Empty;
    string str = memberExpression.ToString();
    return str.Substring(str.IndexOf(".", StringComparison.Ordinal) + 1);
  }

  public static List<string> GetNames<T>(Expression<Func<T, object[]>> expression)
  {
    List<string> names = new List<string>();
    if (expression == null || !(expression.Body is NewArrayExpression body))
      return names;
    foreach (Expression expression1 in body.Expressions)
    {
      string name = Lambda.GetName(expression1);
      if (!string.IsNullOrWhiteSpace(name))
        names.Add(name);
    }
    return names;
  }

  public static string GetLastName(Expression expression, bool right = false)
  {
    MemberExpression memberExpression = Lambda.GetMemberExpression(expression, right);
    if (memberExpression == null || Lambda.IsValueExpression((Expression) memberExpression))
      return string.Empty;
    string str = memberExpression.ToString();
    return str.Substring(str.LastIndexOf(".", StringComparison.Ordinal) + 1);
  }

  private static bool IsValueExpression(Expression expression)
  {
    if (expression == null)
      return false;
    switch (expression.NodeType)
    {
      case ExpressionType.Constant:
        return true;
      case ExpressionType.MemberAccess:
        return Lambda.IsValueExpression(((MemberExpression) expression).Expression);
      default:
        return false;
    }
  }

  public static List<string> GetLastNames<T>(Expression<Func<T, object[]>> expression)
  {
    List<string> lastNames = new List<string>();
    if (expression == null || !(expression.Body is NewArrayExpression body))
      return lastNames;
    foreach (Expression expression1 in body.Expressions)
    {
      string lastName = Lambda.GetLastName(expression1);
      if (!string.IsNullOrWhiteSpace(lastName))
        lastNames.Add(lastName);
    }
    return lastNames;
  }

  public static object GetValue(Expression expression)
  {
    if (expression == null)
      return (object) null;
    switch (expression.NodeType)
    {
      case ExpressionType.Call:
        return Lambda.GetMethodCallExpressionValue(expression);
      case ExpressionType.Constant:
        return Lambda.GetConstantExpressionValue(expression);
      case ExpressionType.Convert:
        return Lambda.GetValue(((UnaryExpression) expression).Operand);
      case ExpressionType.Equal:
      case ExpressionType.GreaterThan:
      case ExpressionType.GreaterThanOrEqual:
      case ExpressionType.LessThan:
      case ExpressionType.LessThanOrEqual:
      case ExpressionType.NotEqual:
        return Lambda.HasParameter(((BinaryExpression) expression).Left) ? Lambda.GetValue(((BinaryExpression) expression).Right) : Lambda.GetValue(((BinaryExpression) expression).Left);
      case ExpressionType.Lambda:
        return Lambda.GetValue(((LambdaExpression) expression).Body);
      case ExpressionType.MemberAccess:
        return Lambda.GetMemberValue((MemberExpression) expression);
      case ExpressionType.Not:
        return expression.Type == typeof (bool) ? (object) false : (object) null;
      default:
        return (object) null;
    }
  }

  private static bool HasParameter(Expression expression)
  {
    if (expression == null)
      return false;
    switch (expression.NodeType)
    {
      case ExpressionType.Convert:
        return Lambda.HasParameter(((UnaryExpression) expression).Operand);
      case ExpressionType.MemberAccess:
        return Lambda.HasParameter(((MemberExpression) expression).Expression);
      case ExpressionType.Parameter:
        return true;
      default:
        return false;
    }
  }

  private static object GetMethodCallExpressionValue(Expression expression)
  {
    MethodCallExpression methodCallExpression = (MethodCallExpression) expression;
    object callExpressionValue = Lambda.GetValue(methodCallExpression.Arguments.FirstOrDefault<Expression>());
    if (callExpressionValue != null)
      return callExpressionValue;
    return methodCallExpression.Object == null ? methodCallExpression.Type.InvokeMember(methodCallExpression.Method.Name, BindingFlags.InvokeMethod, (Binder) null, (object) null, (object[]) null) : Lambda.GetValue(methodCallExpression.Object);
  }

  private static object GetMemberValue(MemberExpression expression)
  {
    if (expression == null)
      return (object) null;
    FieldInfo member1 = expression.Member as FieldInfo;
    if (member1 != (FieldInfo) null)
    {
      object constantExpressionValue = Lambda.GetConstantExpressionValue(expression.Expression);
      return member1.GetValue(constantExpressionValue);
    }
    PropertyInfo member2 = expression.Member as PropertyInfo;
    if (member2 == (PropertyInfo) null)
      return (object) null;
    if (expression.Expression == null)
      return member2.GetValue((object) null);
    object memberValue = Lambda.GetMemberValue(expression.Expression as MemberExpression);
    if (memberValue != null)
      return member2.GetValue(memberValue);
    return member2.PropertyType == typeof (bool) ? (object) true : (object) null;
  }

  private static object GetConstantExpressionValue(Expression expression)
  {
    return ((ConstantExpression) expression).Value;
  }

  public static Operator? GetOperator(Expression expression)
  {
    if (expression == null)
      return new Operator?();
    switch (expression.NodeType)
    {
      case ExpressionType.Call:
        return Lambda.GetMethodCallExpressionOperator(expression);
      case ExpressionType.Convert:
        return Lambda.GetOperator(((UnaryExpression) expression).Operand);
      case ExpressionType.Equal:
        return new Operator?(Operator.Equal);
      case ExpressionType.GreaterThan:
        return new Operator?(Operator.Greater);
      case ExpressionType.GreaterThanOrEqual:
        return new Operator?(Operator.GreaterEqual);
      case ExpressionType.Lambda:
        return Lambda.GetOperator(((LambdaExpression) expression).Body);
      case ExpressionType.LessThan:
        return new Operator?(Operator.Less);
      case ExpressionType.LessThanOrEqual:
        return new Operator?(Operator.LessEqual);
      case ExpressionType.NotEqual:
        return new Operator?(Operator.NotEqual);
      default:
        return new Operator?();
    }
  }

  private static Operator? GetMethodCallExpressionOperator(Expression expression)
  {
    switch (((MethodCallExpression) expression)?.Method?.Name?.ToLower())
    {
      case "contains":
        return new Operator?(Operator.Contains);
      case "endswith":
        return new Operator?(Operator.Ends);
      case "startswith":
        return new Operator?(Operator.Starts);
      default:
        return new Operator?();
    }
  }

  public static ParameterExpression GetParameter(Expression expression)
  {
    if (expression == null)
      return (ParameterExpression) null;
    switch (expression.NodeType)
    {
      case ExpressionType.Call:
        return Lambda.GetParameter(((MethodCallExpression) expression).Object);
      case ExpressionType.Convert:
        return Lambda.GetParameter(((UnaryExpression) expression).Operand);
      case ExpressionType.Equal:
      case ExpressionType.GreaterThan:
      case ExpressionType.GreaterThanOrEqual:
      case ExpressionType.LessThan:
      case ExpressionType.LessThanOrEqual:
      case ExpressionType.NotEqual:
        return Lambda.GetParameter(((BinaryExpression) expression).Left);
      case ExpressionType.Lambda:
        return Lambda.GetParameter(((LambdaExpression) expression).Body);
      case ExpressionType.MemberAccess:
        return Lambda.GetParameter(((MemberExpression) expression).Expression);
      case ExpressionType.Parameter:
        return (ParameterExpression) expression;
      default:
        return (ParameterExpression) null;
    }
  }

  public static List<List<Expression>> GetGroupPredicates(Expression expression)
  {
    List<List<Expression>> result = new List<List<Expression>>();
    if (expression == null)
      return result;
    Lambda.AddPredicates(expression, result, Lambda.CreateGroup(result));
    return result;
  }

  private static List<Expression> CreateGroup(List<List<Expression>> result)
  {
    List<Expression> group = new List<Expression>();
    result.Add(group);
    return group;
  }

  private static void AddPredicates(
    Expression expression,
    List<List<Expression>> result,
    List<Expression> group)
  {
    switch (expression.NodeType)
    {
      case ExpressionType.AndAlso:
        Lambda.AddPredicates(((BinaryExpression) expression).Left, result, group);
        Lambda.AddPredicates(((BinaryExpression) expression).Right, result, group);
        break;
      case ExpressionType.Lambda:
        Lambda.AddPredicates(((LambdaExpression) expression).Body, result, group);
        break;
      case ExpressionType.OrElse:
        Lambda.AddPredicates(((BinaryExpression) expression).Left, result, group);
        Lambda.AddPredicates(((BinaryExpression) expression).Right, result, Lambda.CreateGroup(result));
        break;
      default:
        group.Add(expression);
        break;
    }
  }

  public static int GetConditionCount(LambdaExpression expression)
  {
    return expression == null ? 0 : ((IEnumerable<string>) expression.ToString().Replace("AndAlso", "|").Replace("OrElse", "|").Split('|')).Count<string>();
  }

  public static TAttribute GetAttribute<TAttribute>(Expression expression) where TAttribute : Attribute
  {
    return Lambda.GetMember(expression).GetCustomAttribute<TAttribute>();
  }

  public static TAttribute GetAttribute<TEntity, TProperty, TAttribute>(
    Expression<Func<TEntity, TProperty>> propertyExpression)
    where TAttribute : Attribute
  {
    return Lambda.GetAttribute<TAttribute>((Expression) propertyExpression);
  }

  public static TAttribute GetAttribute<TProperty, TAttribute>(
    Expression<Func<TProperty>> propertyExpression)
    where TAttribute : Attribute
  {
    return Lambda.GetAttribute<TAttribute>((Expression) propertyExpression);
  }

  public static IEnumerable<TAttribute> GetAttributes<TEntity, TProperty, TAttribute>(
    Expression<Func<TEntity, TProperty>> propertyExpression)
    where TAttribute : Attribute
  {
    return Lambda.GetMember((Expression) propertyExpression).GetCustomAttributes<TAttribute>();
  }

  public static ConstantExpression Constant(object value, Expression expression = null)
  {
    Type type = Lambda.GetType(expression);
    return type == (Type) null ? Expression.Constant(value) : Expression.Constant(value, type);
  }

  public static ParameterExpression CreateParameter<T>() => Expression.Parameter(typeof (T), "t");

  public static Expression<Func<T, bool>> Equal<T>(string propertyName, object value)
  {
    ParameterExpression parameter = Lambda.CreateParameter<T>();
    return parameter.Property(propertyName).Equal(value).ToPredicate<T>(parameter);
  }

  public static Expression<Func<T, bool>> NotEqual<T>(string propertyName, object value)
  {
    ParameterExpression parameter = Lambda.CreateParameter<T>();
    return parameter.Property(propertyName).NotEqual(value).ToPredicate<T>(parameter);
  }

  public static Expression<Func<T, bool>> Greater<T>(string propertyName, object value)
  {
    ParameterExpression parameter = Lambda.CreateParameter<T>();
    return parameter.Property(propertyName).Greater(value).ToPredicate<T>(parameter);
  }

  public static Expression<Func<T, bool>> GreaterEqual<T>(string propertyName, object value)
  {
    ParameterExpression parameter = Lambda.CreateParameter<T>();
    return parameter.Property(propertyName).GreaterEqual(value).ToPredicate<T>(parameter);
  }

  public static Expression<Func<T, bool>> Less<T>(string propertyName, object value)
  {
    ParameterExpression parameter = Lambda.CreateParameter<T>();
    return parameter.Property(propertyName).Less(value).ToPredicate<T>(parameter);
  }

  public static Expression<Func<T, bool>> LessEqual<T>(string propertyName, object value)
  {
    ParameterExpression parameter = Lambda.CreateParameter<T>();
    return parameter.Property(propertyName).LessEqual(value).ToPredicate<T>(parameter);
  }

  public static Expression<Func<T, bool>> Starts<T>(string propertyName, object value)
  {
    ParameterExpression parameter = Lambda.CreateParameter<T>();
    return parameter.Property(propertyName).StartsWith(value).ToPredicate<T>(parameter);
  }

  public static Expression<Func<T, bool>> Ends<T>(string propertyName, object value)
  {
    ParameterExpression parameter = Lambda.CreateParameter<T>();
    return parameter.Property(propertyName).EndsWith(value).ToPredicate<T>(parameter);
  }

  public static Expression<Func<T, bool>> Contains<T>(string propertyName, object value)
  {
    ParameterExpression parameter = Lambda.CreateParameter<T>();
    return parameter.Property(propertyName).Contains(value).ToPredicate<T>(parameter);
  }

  public static Expression<Func<T, bool>> ParsePredicate<T>(
    string propertyName,
    object value,
    Operator @operator)
  {
    ParameterExpression parameter = Lambda.CreateParameter<T>();
    return parameter.Property(propertyName).Operation(@operator, value).ToPredicate<T>(parameter);
  }
}
